package rabid;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.text.DecimalFormat;
import java.util.List;

import common.Constants;
import common.UserInteractionException;
import common.Util;

/**
 * This is the main process of the RABID program. This class reads
 * the user's commands and handles them accordingly.
 * 
 * @author Andrew Bernard
 */
public class QueryEngine {
  private BufferedReader input;
  private IndexManager indexMgr;
  private List queryResults = null;
  private DecimalFormat pctText = new DecimalFormat("##0.00%");
  
  private EngineStats engineStats = new EngineStats();  
  private class EngineStats {
    public int statsCommandCalls = 0;
    public int indexCommandCalls = 0;
    public int queryCommandCalls = 0;
    public int refineCommandCalls = 0;
    public int showCommandCalls = 0;
    public int nextCommandCalls = 0;
    public double retrievalRequests = 0;
    public double falsePositives = 0;
  }
    
  public QueryEngine() throws IOException, FileNotFoundException {
    indexMgr = new IndexManager();
  }
  
  public void run() throws IOException {
    input = new BufferedReader(new InputStreamReader(System.in));
    
    while(true) {
      String command = prompt().trim().toLowerCase();
      try {
        call(command);
      }
      catch (UserInteractionException ex) {
        outln(ex.getMessage());
      }
    }
  }
  
  private String prompt() throws IOException {
    System.out.print("\n??? ");
    return input.readLine();
  }
  
  public void call(String command) 
  throws IOException, UserInteractionException {
    if(command.equals("stats")) {
      engineStats.statsCommandCalls++;      
      outln(indexMgr.getCorpusDetails());
    }
    
    else if(command.equals("index")) {
      engineStats.indexCommandCalls++;
      outln(indexMgr.getIndexDetails());
    }
    
    else if(command.startsWith("query")) {
      engineStats.queryCommandCalls++;
      
      String queryString = command.substring(command.indexOf("query")+5).trim(); 
      //+5 puts the string index after the command
      
      if(queryString.equals(""))
        throw new UserInteractionException(Constants.ERR_SYNTAX);
      else {
        queryString = removeStopWords(queryString);
        queryResults = indexMgr.runQuery(queryString);
        outln(queryResults);
      }
    }
    
    else if(command.startsWith("similar to")) {
      String fileName = command.substring(command.indexOf("similar to")+10).trim();
      List similarFiles = indexMgr.getSimilarFiles(fileName, 7);
      outln(similarFiles);
    }
    
    else if(command.equals("quit")) {
      outln(getEngineStats());
      System.exit(0);
    }
    
    else
      throw new UserInteractionException(Constants.ERR_SYNTAX);
  }
  
  private String removeStopWords(String string) 
  throws IOException, UserInteractionException {
    StringReader reader = new StringReader(string);
    String wordText = "";
    
    for(int ch = reader.read(); ch != Constants.EOF; ch = reader.read()) {
      if(ch == ' ' || Util.peek(reader) == Constants.EOF) {
        
        if(Util.peek(reader) == Constants.EOF) wordText += (char)ch;
        
        if(wordText.length() > 0) {          
          if(indexMgr.isStopWord(wordText)) {
            string = removeTextFromString(wordText, string).trim();            
          }
          wordText = new String();
        }
      }
      else
        wordText += (char)ch;
    }
    return string;
  }
  
  private String removeTextFromString(String text, String string) {
    String newString;
    int startIndex = string.indexOf(text);
    if(startIndex != -1) {
      int endIndex = startIndex + text.length();    
      String left = string.substring(0, startIndex);
      String right = string.substring(endIndex);
      newString = left.concat(right);
    }
    else
      newString = string;
    return newString;
  }
  
  private String getEngineStats() {
    pctText.setMinimumFractionDigits(1);
    String falsePositiveRate;
    if(engineStats.retrievalRequests > 0)
      falsePositiveRate = pctText.format(engineStats.falsePositives / engineStats.retrievalRequests);
    else
      falsePositiveRate = "N/A";
    
    String indexSizeRatio;
    if(indexMgr.getCorpusFileSize() > 0)
      indexSizeRatio = pctText.format((double)indexMgr.getIndexFileSize() / (double)indexMgr.getCorpusFileSize());
    else
      indexSizeRatio = "0%";
    
    StringBuffer stats = new StringBuffer();
    stats.append("\nFalse Positive Rate: "+falsePositiveRate)
         .append("\nIndex is "+indexSizeRatio+" of the corpus size")
         .append("\n\n-------- Commands Executed --------")
         .append("\nSTATS: ").append(engineStats.statsCommandCalls)
         .append("\nINDEX: ").append(engineStats.indexCommandCalls)
         .append("\nQUERY: ").append(engineStats.queryCommandCalls)
         .append("\nREFINE: ").append(engineStats.refineCommandCalls)
         .append("\nSHOW: ").append(engineStats.showCommandCalls)
         .append("\nNEXT: ").append(engineStats.nextCommandCalls)
         .append("\nQUIT: 1");
    return stats.toString();
  }
    
  /** This is here because I'm lazy ;) */
  private static void outln(Object obj) {
    System.out.println(obj);
  }
}
